home *** CD-ROM | disk | FTP | other *** search
- #
- # system.imgtclrc -- initialization for imgtcl module.
- #
-
- #
- # Execute the autogenerated stuff and the manually generated stuff...
- #
- if {[info exists env(IMGTCL_VERBOSE)]} {
- puts -nonewline stderr "dlopening imgtcl.so..."
- }
- dlopen libimgtcl.so init imgtcl_init
- if {[info exists env(IMGTCL_VERBOSE)]} {
- puts stderr "done."
- }
-
- # ---------------------------------------------------------------------------
-
- # comment (not perfect; e.g. it evaluates bracketed expressions in comments
- proc // {args} {}
- proc XXX {args} {puts "XXX $args"}
-
- // this sucks...
- // switch {5} {
- 3 {puts "three"}
- 2 {puts "two"}
- $five {puts "FIVE"}
- default {puts "the default"}
- }
-
- # ----------------------------------------------------------------------------
- # System constants...
- # ----------------------------------------------------------------------------
-
- # "const" is like "set" but it makes the variable read-only,
- # and adds it to the list of consts.
- proc const {name value} {
- global $name
- set $name $value
- trace variable $name w attempted_write_to_const
- global consts
- lappend consts $name
- }
- proc attempted_write_to_const {name element operation} {
- if {$element != ""} {
- set name ${name}($element)
- }
- error "it's a constant, you dummy."
- }
-
- const NULL 0
- # XXX umm... uhh... how to distinguish between NULL and an empty string?
- const HZ 100
- # XXX don't hard-code in here!
-
- const 0 0; # for things like $[rImg.getResampType]
-
-
-
- # ----------------------------------------------------------------------------
- # IL Constants...
- # ----------------------------------------------------------------------------
-
- const FALSE 0
- const TRUE 1
-
- proc unimplemented {name} {
- global ilOKAY
- proc $name {args} "
- puts {$name not implemented yet...}
- return $ilOKAY
- "
- }
-
- proc unimplemented_object {classname objname} {
- global ilOKAY
- proc $objname {methodname args} "
- puts \"invoked object $objname's method $classname::\$methodname which is not implemented yet...\"
- return $ilOKAY
- "
- }
-
- proc unimplemented_class {classname} {
- proc $classname {objname args} "
- puts \"created object \$objname of class $classname which is not implemented yet...\"
- unimplemented_object $classname \$objname
- return \$objname
- "
- }
- proc unimplemented_ptrclass {classname} {
- proc $classname {objname args} "
- return \$objname
- "
- }
-
- # -----------------------------------------------------------------------------
- # IL Stubs...
- # -----------------------------------------------------------------------------
-
- unimplemented_ptrclass ilView*
- // XXX should put a trace on pointer variables to make sure they get the right type!
- unimplemented_ptrclass ilImage*
- unimplemented_ptrclass ilImage**
- unimplemented_ptrclass ilFileImg*
- unimplemented_ptrclass ilFileImg**
-
- if {0} {
- # hack to define and use a few structs... I'm not sure what we'll use
- # eventually...
- proc iflXYint {objname args} {
- global $objname
- set ${objname}(x) 0
- set ${objname}(y) 0
- }
- proc iflXYSint {objname args} {
- global $objname
- set ${objname}(x) 0
- set ${objname}(y) 0
- }
-
- proc iflXYSint_array {name init_list} {
- upvar $name A
- set n [llength $init_list]
- for {set i 0} {$i < $n} {incr i} {
- set A($i,x) [lindex [lindex $init_list $i] 0]
- set A($i,y) [lindex [lindex $init_list $i] 1]
- }
- }
- proc iflXYSfloat_array {name init_list} {
- upvar $name A
- for {set i 0} {$i < 3} {incr i} {
- set A($i,x) [lindex [lindex init_list $i] 0]
- set A($i,y) [lindex [lindex init_list $i] 1]
- }
- }
-
- proc short {name} {
- # do nothing
- }
- proc int {name} {
- # do nothing
- }
-
- }
-
- proc getdescription {name} {
- global description
- if {[info exists description($name)]} {
- return $description($name)
- } else {
- return $name
- }
- }
-
- // Support obj.method syntax...
- // I have misgivings about this, since it is a performance drain every time
- // any method command is executed.
- // XXX idea: the first time foo.bar is executed, it could
- // actually create a command called foo.bar;
- // then subsequent calls wouldn't need to go through this "unknown" mechanism.
- // But then these would need to be deleted when the object is deleted,
- // which would be a bloody mess to keep track of...
-
- rename unknown _unknown_pre_il
- proc unknown {name args} {
-
- #
- # If $name is of the form obj.method, call $obj $method.
- #
- if {[scan $name {%[^.].%s} obj method] == 2} {
- return [uplevel $obj $method $args]
- }
-
- #
- # If $name is of the form ptr->method, call $$ptr $method.
- #
- if {[scan $name {%[^-]->%s} ptr method] == 2} {
- return [uplevel [uplevel set $ptr] $method $args]
- }
-
- #
- # If $name is of the form (classname*)addr, call $classname:: $addr.
- #
- if {[scan $name {(%[_a-zA-Z0-9]*)%s} classname addr] == 2} {
- return [uplevel $classname:: $addr $args]
- }
-
- #
- # If $name is of the form (struct_or_scalar_name {dims})addr,
- # call $struct_or_scalarname:: $dims $addr
- #
- if {[scan $name {(%[_a-zA-Z0-9] {%[^\}]})%s} structname dims addr] == 3} {
- return [va_uplevel _array_command $structname $dims $addr $args]
- }
-
- #
- # Call the default "unknown".
- # The following would do it:
- # return [uplevel _unknown_pre_il $name $args]
- # except that we want to discard the stack trace from this point down.
- # So instead we catch the error (if there is one)
- # and pass it up with an empty stack trace.
- #
- set code [catch {uplevel _unknown_pre_il $name $args} result]
- return -code $code $result
- }
-
-
- # Wanted to call this "array", but tcl already has
- # such a command...
- proc new {type name {dims ""} {equals ""} {initlist ""}} {
- global sizeof
- if {! [regexp {^[_a-zA-Z]} $name]} {
- # no name supplied-- shift args accordingly
- set initlist $equals
- set equals $dims
- set dims $name
- set name ""
- }
- if {$dims == ""} {
- return -code 1 "dims not specified properly"
- }
-
- # XXX here, check whether a variable or procedure
- # of this name exists, and if so, reject.
- # (Then won't need the "write" trace below, only the "unset" trace.
-
- if { [regexp {\*$} $type] } {
- set sizeoftype $sizeof(void*)
- } else {
- set sizeoftype $sizeof($type)
- }
-
- if {$equals == "addr" && [string range $initlist 0 2] != "0x"} {
- # memory is being passed to us, don't allocate any, just use it
- set equals ""
- set addr $initlist
- set initlist ""
- set ownMemory 0
- } else {
- set addr [malloc [expr $sizeoftype * [join $dims *]]]
- if {! $addr} {
- return -code 1 "malloc([expr $sizeoftype * [join $dims *]]) failed"
- }
- set ownMemory 1
- }
- set result "($type {$dims})$addr"
-
- if {$addr != 0} {
- if {$equals != "" || $initlist != ""} {
- if {$equals != "=" || $initlist == ""} {
- free $addr
- return -code 1 "invalid initializer \"$equals $initlist\""
- }
- if {[catch {$result = $initlist} error_result] == 1} {
- free $addr
- return -code 1 $error_result
- }
- }
- }
-
- if {$name != ""} {
- #
- # Set the named variable to the string containing
- # the address and indexing info...
- # Note that this will trigger cleaning up of any
- # previous value of the variable and command,
- # so it must be done before we define the command.
- #
- uplevel [list set $name $result]
-
- #
- # Create a command called name...
- # This doesn't accomplish much in the current implementation,
- # but if the "new" command is rewritten in C,
- # it could allocate a struct describing the array and strides
- # and use this as the client data,
- # so that they wouldn't need to be recalculated every dang
- # time the array is derefed.
- #
-
- set hidden_name [_localproc_uniquename]
- if {[info commands $name] != {}} {
- rename $name $hidden_name
- }
- proc $name {args} "
- va_call _array_command $type \{$dims\} $addr \$args
- "
-
- # set the trace on the variable to free the space and delete the command
- # unless this was an "addr" style initialization in which case we don't
- # own the memory
- if ($ownMemory) {
- uplevel [list trace variable $name wu \
- "array_unset_or_reset_callback \"$result\" $hidden_name"]
- }
- }
-
- return $result
- }
-
- #
- # Calling a function and passing it the trailing varargs "args" arguments
- # seems to be extremely awkward in tcl; here is a function that does it.
- # Takes any number of arguments; the first one should be a command name, and
- # the last one should be an "args" list that will get expanded
- # and passed to the command along with the preceding arguments.
- #
- proc va_call {args} {
- set nargs [llength $args]
- set lastargs [lindex $args [expr $nargs - 1]]
- set firstargs [lrange $args 0 [expr $nargs - 2]]
- eval [concat $firstargs $lastargs]
- }
- proc va_uplevel {args} {
- # Note, does not understand the "level" argument of uplevel
- set nargs [llength $args]
- set lastargs [lindex $args [expr $nargs - 1]]
- set firstargs [lrange $args 0 [expr $nargs - 2]]
- uplevel [concat $firstargs $lastargs]
- }
-
- #XXX
- proc printvar {name} {
- upvar $name value
- puts "$name = \"$value\""
- }
-
- proc _array_command {type dims addr args} {
- # Suppose A is "(iflSize {2 3})0x123456".
- # Then "A 0" or "A {0} should return "(iflSize {3})0x12345".
- # "A + 1" should return "(iflSize {1 3})0x12345a"
- # "A 0 0" or "A {0 0}" should return "{512 512 1 3}"
- # "A 0 0 x" or "A {0 0} x" should return "512"
- # "A 0 0 x = 20" or "A {0 0} x = 20" should set A[0][0].x = 20
- global sizeof
-
- #printvar type
- #printvar dims
- #printvar addr
- #printvar args
-
- #
- # Set inds equal to the concatenation of all the
- # initial args that look like numbers or lists of numbers.
- #
-
- set inds ""
- while {[regexp {^[0-9]} [set firstarg [lindex $args 0]]]} {
- set inds [concat $inds $firstarg]
- set args [lreplace $args 0 0]
- }
-
- #printvar inds
- #printvar args
- #puts ""
-
- set ndims [llength $dims]
- set ninds [llength $inds]
-
- if {$ninds > $ndims} {
- error "Too many indices $inds for ($type {$dims})$addr"
- }
-
- if { [regexp {\*$} $type] } {
- set mangledtype "void_ptr_"
- set sizeoftype $sizeof(void*)
- } else {
- set mangledtype $type
- set sizeoftype $sizeof($type)
- }
-
- #
- # Peel off a dimension and an index, until there are no more indices...
- #
- while {$ninds > 0} {
- set dim0 [lindex $dims 0]
- set ind0 [lindex $inds 0]
-
- if {$ind0 < 0 || $ind0 >= $dim0} {
- error "Index \"$ind0\" out of bounds \"$dim0\" for ($type {$dims})$addr"
- }
-
- set addr [expr $addr + $ind0 * $sizeoftype * [join $dims *] / $dim0]
- set addr [format %#x $addr] ;# XXX possible performance drain here
- set dims [lrange $dims 1 end]
- set inds [lrange $inds 1 end]
- incr ndims -1
- incr ninds -1
- }
-
- if {$ndims > 0} {
- if {$args == {}} {
- # This is the syntax for returning the array as a list
- set args "="
- }
- if {[lindex $args 0] == "="} {
- switch [llength $args] {
- 1 {
- #
- # Return the entire C array as a list
- #
- set result {}
- set dim0 [lindex $dims 0]
- for {set i 0} {$i < $dim0} {incr i} {
- lappend result [_array_command $type $dims $addr $i =]
- }
- return $result
- }
- 2 {
- #
- # Set the C array from the explicit list given
- #
- set initlist [lindex $args 1]
- set ninits [llength $initlist]
- if {$ninits > [lindex $dims 0]} {
- error "Initializer list $initlist too long for ($type {$dims})$addr"
- }
- for {set i 0} {$i < $ninits} {incr i} {
- _array_command $type $dims $addr $i = [lindex $initlist $i]
- }
- return ""
- }
- default {
- puts [llength $args]
- error "Bad initializer \"$args\" for ($type {$dims})$addr"
- }
- }
- } elseif {[lindex $args 0] == "+"} {
- if {[llength $args] != 1} {
- ....
- XXX
- }
- } else {
- error "Unrecognized argument syntax \"$args\" for ($type {$dims})$addr"
-
- }
- }
-
- # At this point, $ndims and $ninds are both 0
-
- if {$args == "="} {
- return [$mangledtype:: $addr]
- } else {
- return [va_call $mangledtype:: $addr $args]
- }
- }
-
- proc array_unset_or_reset_callback {old_value hidden_name name element op} {
- # XXX The following may be a performance drain...
- global env
- if {[info exists env(IMGTCL_UNSET_VERBOSE)]} {
- puts stderr "In array unset cb, name=$name, elt=$element, op=$op, old value=$old_value"
- }
-
- free $old_value
- rename $name ""
- if {[info commands $hidden_name] != {}} {
- rename $hidden_name $name
- }
- uplevel [list trace vdelete $name wu \
- "array_unset_or_reset_callback \"$old_value\" $hidden_name"]
- }
-
- #
- # "localproc" is like "proc" but it
- # creates a procedure that is local to the current stack frame;
- # i.e. it gets destroyed and the previous implementation (if any)
- # is restored when the current stack frame is destroyed.
- #
- # This is complicated due to ugliness in the unset-trace implementation.
- # For example, to implement a local procedure "foo",
- # call
- # localproc foo {...} {
- # ...
- # }
- # How this is implemented:
- # chooses a unique name like __localproc_uniquename_2983
- # if there's already a function named foo,
- # then rename it __localproc_uniquename_2983
- # creates the function foo as specified
- #
- # set __localproc_uniquename_2983(foo) "arbitrary value"
- # put a trace on __localproc_uniquename_2983(foo)
- # so that when it is unset, we will
- # restore the original procedure foo.
- # (Note: The reason we encode the procedure name
- # and its "hidden name" in the name of the variable
- # rather than in the contents of the variable
- # is that the contents of the variable
- # are undefined while the unset-trace-callback
- # is being executed (which seems silly to me,
- # but that's the way it is)).
- # set __localproc_hidden_name(foo) __localproc_uniquename_2983
- # (Note: The reason we also set __localproc_hidden_name(foo)
- # is so that we can implement a procedure "unlocalproc"
- # which will restore the original foo;
- # it needs to be able to look up the hidden name
- # knowing only the name "foo", and it can't do this
- # from only the variable __localproc_uniquename_2983(foo).
- #
- #
-
- proc localproc {procname args body} {
- if {[uplevel info exists __localproc_hidden_name($procname)]} {
- error "localproc \"$procname\" already exists"
- }
- set hidden_name [_localproc_uniquename]
- if {[info commands $procname] != {}} {
- rename $procname $hidden_name
- }
-
- uplevel [list set __localproc_hidden_name($procname) $hidden_name]
- uplevel [list trace variable __localproc_hidden_name($procname) wu \
- "_localproc_unset_trace $procname $hidden_name"]
-
- uplevel [list proc $procname $args $body]
- }
-
- proc unlocalproc {procname} {
- # The unset-trace callback is what does the real work...
- uplevel [list unset __localproc_hidden_name($procname)]
- }
-
- proc _localproc_unset_trace {procname hidden_name name elt op} {
- rename $procname ""
- if {[info commands $hidden_name] != {}} {
- rename $hidden_name $procname
- }
- }
-
- set __localproc_uniquename_i 0
- proc _localproc_uniquename {} {
- global __localproc_uniquename_i
- return __localproc_uniquename_[incr __localproc_uniquename_i]
- }
-
- // {
-
- # -----------------------------------------------------------------------------
- # Experimenting with calling-with-named-args...
-
- # The original way... (note that the y=0 default is useless)
- proc foo {a b {c 0}} {}
- proc bar {x {y 0} z args} {}
-
- # Split into the "real" functions and the user-friendly "wrapper" functions...
- proc _foo {a b {c 0}} {}
- proc _bar {x {y 0} z args} {}
-
- proc foo {args} {
- set c 0
- foreach
- }
-
-
- }
-
- # Set prompt for interactive sessions...
- # Do this last; if an error occurred before this point,
- # the user will know something is wrong because the prompt is unfamiliar...
- set tcl_prompt1 "puts -nonewline \"imgtcl> \""
- set tcl_prompt2 "puts -nonewline \"> \""
-
- return; # so return value will be "" and not the result of the previous command
-
- }
-